﻿using System;

namespace AcademicPlanner.Domain.Models
{
	/// <summary>
	/// List of validation error codes in the domain layer of the AcademicPlanner application.
	/// </summary>
	/// <version>1.0</version>
	/// <since>1.0</since>
	public enum InvalidModelPropertyErrorCode
	{
		NONE,
		REQUIRED,
		INVALID_EMAIL,
		NOT_UNIQUE,
		NOT_PRESENT,
		NOT_ALPHANUMERIC,
		NOT_ALPHA,
		TOO_SHORT,
		TOO_LONG,
		DISALLOWED_SEQUENCE,
		INVALID_FORMAT
	}

	/// <summary>
	/// Represents an exception indicating validation errors of possible
	/// values of a <c>Model</c>.
	/// </summary>
	/// <version>1.0</version>
	/// <since>1.0</since>
    public class InvalidModelPropertiesException : NotCriticalDomainException
    {
		/// <summary>
		/// Collection of validation errors associated with this InvalidModelPropertiesException.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected InvalidModelPropertiesErrorCollection errors;


		/// <summary>
		/// Gets the collection of validation errors associated with this InvalidModelPropertiesException.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public InvalidModelPropertiesErrorCollection Errors
		{
			get { return errors; }
		}


		/// <summary>
		/// Constructs a InvalidModelPropertiesException to indicate a validation error
		/// with one single property of a <c>Model</c>. This method effectively creates
		/// a InvalidModelPropertiesErrorCollection with one element in it.
		/// </summary>
		/// <param name="pModel">
		/// The name (class name) of the <c>Model</c> whose possible property value is invalid.
		/// </param>
		/// <param name="pProperty">The name of the property whose possible value is invalid.</param>
		/// <param name="pValidationCode">The validation error code.</param>
		/// <param name="pCode">The application level error code.</param>
		/// <seealso cref="AcademicPlanner.Domain.NotCriticalDomainException.NotCriticalDomainException(DomainErrorCode)"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public InvalidModelPropertiesException(string pModel, string pProperty, 
					InvalidModelPropertyErrorCode pValidationCode, DomainErrorCode pCode)
			: base(pCode)
		{
			var vErrors = new InvalidModelPropertiesErrorCollection(pModel);
			vErrors.AddOuter(pProperty, pValidationCode);
			errors = vErrors;
		}

		/// <summary>
		/// Constructs a InvalidModelPropertiesException with the given InvalidModelPropertiesErrorCollection.
		/// </summary>
		/// <param name="pCode">The application level error code.</param>
		/// <param name="pErrors">The collection of validation errors.</param>
		/// <seealso cref="AcademicPlanner.Domain.NotCriticalDomainException.NotCriticalDomainException(DomainErrorCode)"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public InvalidModelPropertiesException(DomainErrorCode pCode, InvalidModelPropertiesErrorCollection pErrors)
			: base(pCode)
		{
			errors = pErrors;
		}


		/// <summary>
		/// Gets the validation error message associated with a given validation error code.
		/// </summary>
		/// <param name="pCode">The validation error code.</param>
		/// <returns>The validation error message</returns>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public static string GetErrorCodeMessageFormat(InvalidModelPropertyErrorCode pCode)
		{
			string rMsg = "{0} is invalid.";

			switch (pCode)
			{
				case InvalidModelPropertyErrorCode.REQUIRED:
					rMsg = "{0} cannot be blank.";
					break;
				case InvalidModelPropertyErrorCode.INVALID_EMAIL:
					rMsg = "{0} must be a valid email address.";
					break;
				case InvalidModelPropertyErrorCode.NOT_UNIQUE:
					rMsg = "{0} provided already exists.";
					break;
				case InvalidModelPropertyErrorCode.NOT_PRESENT:
					rMsg = "{0} provided does not exist.";
					break;
				case InvalidModelPropertyErrorCode.NOT_ALPHANUMERIC:
					rMsg = "{0} must contain only letters and digits.";
					break;
				case InvalidModelPropertyErrorCode.NOT_ALPHA:
					rMsg = "{0} must contain only letters.";
					break;
				case InvalidModelPropertyErrorCode.TOO_SHORT:
					rMsg = "{0} contains too few characters.";
					break;
				case InvalidModelPropertyErrorCode.TOO_LONG:
					rMsg = "{0} contains too many characters.";
					break;
				case InvalidModelPropertyErrorCode.DISALLOWED_SEQUENCE:
					rMsg = "{0} contains a forbidden sequence of characters.";
					break;
			}

			return rMsg;
		}
    }
}
